package com.ruoyi.business.api;

import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.ruoyi.business.utils.CoordinateTransformUtil;
import com.ruoyi.business.utils.GPS;
import com.ruoyi.common.config.RuoYiConfig;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.JsonUtils;
import com.ruoyi.common.utils.file.FileUploadUtils;
import com.ruoyi.framework.config.ServerConfig;
import lombok.extern.slf4j.Slf4j;
import org.geotools.geojson.feature.FeatureJSON;
import org.geotools.geojson.geom.GeometryJSON;
import org.geotools.kml.KMLConfiguration;
import org.geotools.xsd.PullParser;
import org.opengis.feature.simple.SimpleFeature;
import org.opengis.feature.simple.SimpleFeatureType;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringWriter;
import java.math.BigDecimal;
import java.util.Arrays;
import java.util.Iterator;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @author liutao
 * @version 1.0
 * @description: TODO
 * @date 2024/4/1 16:58
 */
@Slf4j
@RestController
@RequestMapping("/api/kml")
@CrossOrigin(origins = "*")
public class KmlApi {

    @Resource
    private ServerConfig serverConfig;


    @PostMapping(value = "/kml2json", consumes = {"multipart/form-data"})
    public R<Object> kml2Geojson(MultipartFile multipartFile, Integer transType) throws Exception {
        if (multipartFile == null) {
            throw new ServiceException("空文件，请上传kml文件");
        }
        checkFileName(Objects.requireNonNull(multipartFile.getOriginalFilename()));
        String str = kmlToGeojson(multipartFile.getInputStream()).toString();
        JSONObject jsonObj = JSON.parseObject(str);
        transzb(jsonObj, transType);
        checkGeometer(jsonObj);
        return R.ok(jsonObj);
    }

    //过滤一些无geometry的jsonObject
    private void checkGeometer(JSONObject jsonObj) {
        Object features = jsonObj.get("features");
        if (features instanceof JSONArray) {
            JSONArray jsonArray = (JSONArray) features;
            jsonArray = jsonArray.stream().filter(iter -> ((JSONObject) iter).containsKey("geometry")).collect(Collectors.toCollection(JSONArray::new));
            jsonObj.put("features", jsonArray);
        }
    }

    public void transzb(JSONObject jsonObj, Integer transType) {
        if (ObjectUtil.isEmpty(transType)) {
            return;
        }
        for (String key : jsonObj.keySet()) {
            if (key.equals("coordinates")) {
                StringBuilder sb = new StringBuilder();
                JSONArray jsonArray = (JSONArray) jsonObj.get(key);
                for (Object o : jsonArray) {
                    String zbString = (String) o;
                    String[] split = zbString.split(",");
                    double[] transform = CoordinateTransformUtil.transform(new GPS(Double.parseDouble(split[0]), Double.parseDouble(split[1])), transType);
                    sb.append(Arrays.toString(transform)).append(" ");
                }
                sb.deleteCharAt(sb.length() - 1);
                jsonObj.put("coordinates", sb.toString());
                continue;
            }

            Object o = jsonObj.get(key);
            if (o instanceof JSONObject) {
                JSONObject object = (JSONObject) o;
                transzb(object, transType);
            } else if (o instanceof JSONArray) {
                JSONArray jsonArray = (JSONArray) o;
                transJsonArray(jsonArray, transType);
            }

        }


    }

    public void transJsonArray(JSONArray jsonArray, Integer transType) {
        for (Object o : jsonArray) {
            if (o instanceof JSONArray) {
                transJsonArray((JSONArray) o, transType);
            } else {
                if (o instanceof JSONObject) {
                    JSONObject jsonObject = (JSONObject) o;
                    transJsonObject(jsonObject, transType);
                }
            }
        }
    }


    public void transJsonObject(JSONObject jsonObject, Integer transType) {
        for (String key : jsonObject.keySet()) {
            if (key.equals("coordinates")) {
                JSONArray jsonArray = (JSONArray) jsonObject.get(key);
                JSONArray allArray = new JSONArray();
                JSONArray bigArray;
                boolean singeZBFlag = false;
                for (int i = 0; i < jsonArray.size(); i++) {
                    Object o = jsonArray.get(i);
                    if (o instanceof BigDecimal) {
                        bigArray = new JSONArray();
                        double one = ((BigDecimal) jsonArray.get(0)).doubleValue();
                        double two = ((BigDecimal) jsonArray.get(1)).doubleValue();
                        double[] transform = CoordinateTransformUtil.transform(new GPS(one, two), transType);
                        bigArray.add(0, transform[0]);
                        bigArray.add(1, transform[1]);
                        bigArray.add(2, jsonArray.get(2));
                        singeZBFlag = true;
                        //单个坐标 不需要循环
                        jsonObject.put(key, bigArray);
                        break;
                    }

                    //多个坐标数组
                    JSONArray zbArray = jsonArray.getJSONArray(i);
                    JSONArray newzbArray = new JSONArray();
                    double one = ((BigDecimal) zbArray.get(0)).doubleValue();
                    double two = ((BigDecimal) zbArray.get(1)).doubleValue();
                    double[] transform = CoordinateTransformUtil.transform(new GPS(one, two), transType);
                    newzbArray.add(0, transform[0]);
                    newzbArray.add(1, transform[1]);
                    newzbArray.add(2, zbArray.get(2));

                    allArray.add(i, newzbArray);

                }
                if (!singeZBFlag) {
                    jsonObject.put(key, allArray);
                }
                continue;
            }
            Object o = jsonObject.get(key);
            if (o instanceof JSONArray) {
                JSONArray jsonArray = (JSONArray) o;
                transJsonArray(jsonArray, transType);

            } else if (o instanceof JSONObject) {
                JSONObject jsonObject1 = (JSONObject) o;
                transJsonObject(jsonObject1, transType);
            }
        }

    }

    private void checkFileName(String originalFilename) {
        String substring = originalFilename.substring(originalFilename.lastIndexOf("."));
        if (!substring.equals(".kml")) {
            throw new ServiceException("文件格式不是kml，解析失败");
        }

    }

    public StringWriter kmlToGeojson(InputStream input) throws IOException {
        try(StringWriter sw = new StringWriter();) {
            PullParser parser = new PullParser(new KMLConfiguration(), input, SimpleFeature.class);
            FeatureJSON fjson = new FeatureJSON(new GeometryJSON(7));

            SimpleFeature simpleFeature = (SimpleFeature) parser.parse();
            sw.append("{    \"type\": \"FeatureCollection\",    \"features\": [");
            while (simpleFeature != null) {
                SimpleFeatureType featureType = simpleFeature.getFeatureType();
                fjson.setFeatureType(featureType);
                fjson.writeFeature(simpleFeature, sw);
                simpleFeature = (SimpleFeature) parser.parse();
                if (simpleFeature != null) {
                    sw.append(",");
                }
            }
            sw.append("]}");
//            sw.close();
            return sw;
        } catch (Exception e) {
            log.error("KML 文件解析报错：{}", e.getMessage());
            throw new ServiceException("KML文件解析失败。");
        } finally {
            Objects.requireNonNull(input, "KML 文件输入流为空").close();
        }
    }
}
